package sample;
import com.alibaba.fastjson.JSON;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import netscape.javascript.JSObject;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.dom4j.*;
import sample.bean.*;
import sample.bean.cfg.*;
import sample.bean.msg.AddMsgList_item;
import sample.bean.msg.Batchgetcontact;
import sample.bean.msg.WebwxsyncResponse;

import javax.activation.MimetypesFileTypeMap;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Array;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Main extends Application {
    final private String url1="https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=";

    private WebEngine webEngine;
    private String uuid="";
    private int tip=1;
    private String ticket="";


    private Master initResponse;


    private String skey;
    private String wxsid;
    private String wxuin;
    private String pass_ticket;

    private SyncKey synckey=null;
    private SyncKey synccheckkey=null;

    private WebView ercodeView;
    private WebView chatView;
    private WebView contactView;
    private Stage primaryStage;

    private AppConfig appConfig;
    private HashMap<String,Contact> userShowNameMapping=new HashMap<String,Contact>();  //用户池

    final String cfgFileName="cfg.json";
    private Parent root;

    private static Logger logger  =  Logger.getLogger(Main. class );

    private String filterUser="";



    @Override
    public void start(Stage primaryStage) throws Exception{
        loadConfig();
        this.primaryStage=primaryStage;
        primaryStage.setWidth(1200);
        primaryStage.setHeight(680);

        root = FXMLLoader.load(getClass().getResource("/main.fxml"));
        primaryStage.setTitle("微信登陆");
        Scene scene=new Scene(root, 400, 500, Color.GREEN);
        
        primaryStage.setScene(scene);
        primaryStage.show();
        this.ercodeView=(WebView)root.lookup("#ercodeView");
        this.chatView=(WebView)root.lookup("#chatView");
        this.contactView=(WebView)root.lookup("#contactView");
        final WebEngine we=this.ercodeView.getEngine();
        this.webEngine=we;

        CookieManager cookieManager=new CookieManager();
        cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
        CookieHandler.setDefault(cookieManager);

        initView();
        getUUID();
    }



    private void initVievBindEvent(){



        TextField uf=(TextField)root.lookup("#userfilter");
        uf.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                filterUser=newValue;
                showContactList();
            }
        });


        /////////////////////////////////////////////////////////////////////////////////
        ScrollPane sp=(ScrollPane)root.lookup("#autoPane");
        sp.setFitToWidth(true);

        Button chatImg=(Button)root.lookup("#chatImg");
        chatImg.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                FileChooser fileChooser=new FileChooser();
                fileChooser.setTitle("选择图片");
                FileChooser.ExtensionFilter fileExtensions=new FileChooser.ExtensionFilter("图片","*.jpg","*.jpeg","*.png","*.gif");
                fileChooser.getExtensionFilters().add(fileExtensions);
                File chosenFile=fileChooser.showOpenDialog(primaryStage);
                if (chosenFile != null) {
                    webwxsendimg(initResponse.getUser().getUserName(),currentUser,chosenFile);
                    showMsg();
                }
            }
        });

        Button chatMsg=(Button)root.lookup("#chatMsg");
        chatMsg.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                TextArea ta=(TextArea)root.lookup("#chatTextArea");
                String chatContent=ta.getText().trim();
                if (!chatContent.equals("")) {
                    webwxsendmsg(initResponse.getUser().getUserName(),currentUser,chatContent);
                    showMsg();
                    userShowNameMapping.get(currentUser).plusPriority();
                }
            }
        });


        for(int i=1;i<=7;i++) {
            Button btn = (Button) root.lookup("#pb"+i);
            String btnName="#pt"+i;
            btn.setOnAction(new EventHandler<ActionEvent>() {
                public void handle(ActionEvent event) {
                    FileChooser fileChooser=new FileChooser();
                    fileChooser.setTitle("选择图片");
                    FileChooser.ExtensionFilter fileExtensions=new FileChooser.ExtensionFilter("图片","*.jpg","*.jpeg","*.png","*.gif");
                    fileChooser.getExtensionFilters().add(fileExtensions);
                    File chosenFile=fileChooser.showOpenDialog(primaryStage);
                    if (chosenFile != null) {
                        ((TextField)root.lookup(btnName)).setText(chosenFile.getAbsolutePath());
                    }
                }
            });
        }


        for(int i=1;i<=7;i++) {
            ChoiceBox pc1 = (ChoiceBox) root.lookup("#pc"+i);
            String btnName="#pb"+i;
            pc1.getSelectionModel().selectedItemProperty().addListener(
                    new ChangeListener() {
                        @Override
                        public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                            switch (newValue.toString()) {
                                case "禁用":
                                    break;
                                case "图片":
                                    root.lookup(btnName).setVisible(true);
                                    break;
                                case "文本":
                                    root.lookup(btnName).setVisible(false);
                                    break;
                            }
                        }
                    }
            );
        }

        final Button btn=(Button)root.lookup("#grouPush");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                groupPublish();
            }
        });




/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        for(int i=1;i<=24;i++) {
            for(int j=1;j<=2;j++) {
                Button btnimg = (Button) root.lookup("#qb" + i+j);
                String btnName = "#qt"+i+j;
                btnimg.setOnAction(new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent event) {
                        FileChooser fileChooser = new FileChooser();
                        fileChooser.setTitle("选择图片");
                        FileChooser.ExtensionFilter fileExtensions = new FileChooser.ExtensionFilter("图片", "*.jpg", "*.jpeg", "*.png", "*.gif");
                        fileChooser.getExtensionFilters().add(fileExtensions);
                        File chosenFile=fileChooser.showOpenDialog(primaryStage);
                        if (chosenFile != null) {
                            ((TextField) root.lookup(btnName)).setText(chosenFile.getAbsolutePath());
                        }
                    }
                });
            }
        }
        for(int i=1;i<=24;i++) {
            for(int j=1;j<=2;j++) {
                ChoiceBox pc1 = (ChoiceBox) root.lookup("#qc" + i+j);
                String btnName = "#qb" + i+j;
                pc1.getSelectionModel().selectedItemProperty().addListener(
                        new ChangeListener() {
                            @Override
                            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                                switch (newValue.toString()) {
                                    case "禁用":
                                        break;
                                    case "图片":
                                        root.lookup(btnName).setVisible(true);
                                        break;
                                    case "文本":
                                        root.lookup(btnName).setVisible(false);
                                        break;
                                }
                            }
                        }
                );
            }
        }

        final Button btn2=(Button)root.lookup("#reply");
        btn2.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                saveReplyRule();
            }
        });

        final Button remarkbtn=(Button)root.lookup("#remark");
        remarkbtn.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                resetAllUserRemarkName();
            }
        });

        final Button logoutbtn=(Button)root.lookup("#logout");
        logoutbtn.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent event) {
                System.exit(0);
            }
        });
    }

    private void initView(){

        initVievBindEvent();

        ///////////////////////////////////////////
        if (this.appConfig==null){
            return;
        }

        GroupPush gp=this.appConfig.getGroupPush();
        if(gp!=null){
            ArrayList<GroupFilter> gfs=gp.getFilter();
            int index=1;
            for(GroupFilter filter : gfs){
                ChoiceBox c = (ChoiceBox) root.lookup("#c"+index);
                c.setValue(filter.getType());

                TextField t=(TextField) root.lookup("#f"+index);
                t.setText(filter.getContent());
                index++;
            }

            ArrayList<Reply> gcs=gp.getReply();
            index=1;
            for(Reply reply : gcs){
                ChoiceBox c = (ChoiceBox) root.lookup("#pc"+index);
                c.setValue(reply.getType());

                TextField t=(TextField) root.lookup("#pt"+index);
                t.setText(reply.getContent());

                Button b=(Button) root.lookup("#pb"+index);
                if(reply.getType().equals("图片")){
                    b.setVisible(true);
                }else{
                    b.setVisible(false);
                }
                index++;
            }
        }
        ///////////////////////
        ArrayList<ReplyRule> res=this.appConfig.getReplyList();
        if(res!=null) {
            int index = 1;
            for (ReplyRule reply : res) {
                TextField t = (TextField) root.lookup("#qw" + index);
                t.setText(String.join(";", reply.getKeywords()));

                ArrayList<Reply> subreply = reply.getReply();
                int subindex = 1;
                for (Reply rr : subreply) {
                    ChoiceBox c = (ChoiceBox) root.lookup("#qc" + index + subindex);
                    c.setValue(rr.getType());

                    TextField qt = (TextField) root.lookup("#qt" + index + subindex);
                    qt.setText(rr.getContent());

                    Button bb = (Button) root.lookup("#qb" + index + subindex);
                    if (rr.getType().equals("图片")) {
                        bb.setVisible(true);
                    } else {
                        bb.setVisible(false);
                    }
                    subindex++;
                }
                index++;
            }

        }


    }

    private void logout(){
        //https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=1&skey=%40crypt_20b42769_33e7e7692d1c4946cf8d594bc79bd783
    }

    private void groupPublish(){
        ArrayList<GroupFilter> gf=new ArrayList<>();
        for(int i=1;i<=3;i++) {
            ChoiceBox c1=(ChoiceBox)root.lookup("#c"+i);
            TextField f1=(TextField)root.lookup("#f"+i);
            if (!c1.getValue().toString().equals("禁用") && !f1.getText().equals("")) {
                GroupFilter f = new GroupFilter();
                f.setContent(f1.getText());
                f.setType(c1.getValue().toString());
                gf.add(f);
            }
        }
        ArrayList<Reply> gp=new ArrayList<>();
        for(int i=1;i<=7;i++) {
            ChoiceBox c1=(ChoiceBox)root.lookup("#pc"+i);
            TextField f1=(TextField)root.lookup("#pt"+i);
            if (!c1.getValue().toString().equals("禁用") && !f1.getText().equals("")) {
                Reply f = new Reply();
                f.setContent(f1.getText());
                f.setType(c1.getValue().toString());
                gp.add(f);
            }
        }
        GroupPush gps=new GroupPush();
        gps.setFilter(gf);
        gps.setReply(gp);
        this.appConfig.setGroupPush(gps);
        saveConfig();

        doPublish();

    }

    private Set<String> cloneSet(Set<String> source){
        Set<String> s=new HashSet<>();
        for(String i:source){
            s.add(i);
        }
        return s;
    }

    private void doPublish(){
        ArrayList<GroupFilter> fl=this.appConfig.getGroupPush().getFilter();
        //ArrayList<String> userName=new ArrayList<>();
        Set<String> userName=this.userShowNameMapping.keySet();
        Set<String> result=cloneSet(userName);
        for(GroupFilter f:fl){
            LoopUser:for(String u:userName){
                if (u.startsWith("@@")){//不对群组群发
                    result.remove(u);
                    continue;
                }

                String[] remark=this.userShowNameMapping.get(u).getRemarkName().split("\\|\\|");
                if(remark.length<3){
                    result.remove(u);
                    continue;
                }
                String[] tags=remark[1].split(",");
                boolean include=false;
                for(String s:tags){
                    if(s.equals(f.getContent())) {
                        include=true;
                        if (f.getType().equals("排除")) {
                            result.remove(u);
                            continue LoopUser;
                        }
                    }
                }
                if(f.getType().equals("包含") && include==false){
                    result.remove(u);
                }
            }
        }
        groupPushUserSet=result;
        alertMsg("开始群发","");

        new Thread(new Runnable() {
            @Override
            public void run() {
                    Timer timer=new Timer();
                    timer.schedule(new TimerTask() {
                        public void run() {
                            Iterator<String> it=groupPushUserSet.iterator();
                            if (it.hasNext()){
                                String toUserName = it.next();
                                //String toUserName=initResponse.getUser().getUserName();
                                new Thread(() -> {
                                    ArrayList<Reply> replyList=appConfig.getGroupPush().getReply();
                                    for(Reply r:replyList){
                                        if(r.getType().equals("文本")){
                                            webwxsendmsg(initResponse.getUser().getUserName(),toUserName,r.getContent());
                                        }else{
                                            webwxsendimg(initResponse.getUser().getUserName(),toUserName,r.getContent());
                                        }
                                    }
                                    groupPushUserSet.remove(toUserName);
                                    showMsg();
                                }).start();

                            }else{
                                timer.cancel();
                                alertMsg("群发结束","");
                            }
                        }
                    }, 10, 6000);//定时器的延迟时间及间隔时间
            }
        }).start();

    }
    private Set<String> groupPushUserSet;
    private void saveReplyRule(){
        ArrayList<ReplyRule> gf=new ArrayList<>();
        for(int i=1;i<=24;i++) {
            TextField t=(TextField)root.lookup("#qw"+i);
            if(t.getText().trim().equals("")){
                continue;
            }
            ReplyRule r=new ReplyRule();

            r.setKeywords(new ArrayList<String>(Arrays.asList(t.getText().trim().split(";"))));

            ArrayList<Reply> rl=new ArrayList<>();
            ChoiceBox c1=(ChoiceBox)root.lookup("#qc"+i+1);
            TextField t1=(TextField)root.lookup("#qt"+i+1);
            if (!c1.getValue().toString().equals("禁用") && !t1.getText().equals("")) {
                Reply f = new Reply();
                f.setContent(t1.getText());
                f.setType(c1.getValue().toString());
                rl.add(f);
            }

            c1=(ChoiceBox)root.lookup("#qc"+i+2);
            t1=(TextField)root.lookup("#qt"+i+2);
            if (!c1.getValue().toString().equals("禁用") && !t1.getText().equals("")) {
                Reply f = new Reply();
                f.setContent(t1.getText());
                f.setType(c1.getValue().toString());
                rl.add(f);
            }
            if(rl.size()>0){
                r.setReply(rl);
                gf.add(r);
            }

        }

        if(this.appConfig==null){
            this.appConfig=new AppConfig();
        }
        this.appConfig.setReplyList(gf);

        saveConfig();

        alertMsg("配置保存成功","");
    }

    public void alertMsg(String main,String detail){
        Platform.runLater(
                new Runnable() {
                    @Override
                    public void run() {
                        Alert information = new Alert(Alert.AlertType.INFORMATION, detail);
                        information.setTitle("提示"); //设置标题，不设置默认标题为本地语言的information
                        information.setHeaderText(main); //设置头标题，默认标题为本地语言的information
                        information.initOwner(primaryStage);
                        information.show();
                    }
                }
        );
    }

    public static void main(String[] args) {
        launch(args);
    }

    private String getDeviceID() {
        long a=100000L*100000L*10000L;
        long b=(long)(Math.random()*a*9+a);
        return "e" + Long.toString(b);
    }

    /**
     * 时间戳取反
     * @return
     */
    public static long getTimeStampReverse(){
        long a=System.currentTimeMillis();
        return ~a;
    }

    private void getUUID(){
        String urlStr=this.url1+Long.toString(System.currentTimeMillis());
        BufferedReader read=null;//读取访问结果
        String result="";

        logger.debug("request:"+urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setRequestMethod("GET");
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            connection.disconnect();
            logger.debug("response:"+result);
            String rgex = "window.QRLogin.code = (\\d*); window.QRLogin.uuid = \"(.*)\";";
            List<String> ret=Main.getSubUtil(result,rgex);

            WebEngine contactEngine=contactView.getEngine();

            if(ret.get(0).equals("200")){
                this.uuid=ret.get(1);
                Platform.runLater(
                        new Runnable() {
                            @Override
                            public void run() {
                                webEngine.loadContent("<img id='headpic' width='100%' height='100%' src='https://login.weixin.qq.com/qrcode/"+uuid+"' />");
                                contactEngine.loadContent("请扫码登陆");
                                userShowNameMapping.clear();
                            }
                        }
                );

                    new Thread(() -> {
                        try {
                                this.waitScanQRCode();
                                Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }).start();

            }else{
                System.out.println("----- wrong ---------");
                return;
            }
        }catch (MalformedURLException me){

        }catch(IOException e){

        }
    }

    private void println(String s){
        int max=Math.min(1000000,s.length());
        System.out.println(s.substring(0,max));
    }

    /**
     * 等待扫描二维码
     */
    public void waitScanQRCode(){
        String url2="https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid="+this.uuid+"&tip="+this.tip+"&r=-1791540940&_=";
        String urlStr=url2+Long.toString(System.currentTimeMillis());
        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        String result="";
        logger.debug("request:"+urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            connection.disconnect();
            logger.debug("response:"+result);

            String rgex = "window.code=(\\d*);.*";
            List<String> ret=Main.getSubUtil(result,rgex);
            if(ret.get(0).equals("201")) {
                rgex = "window.code=(\\d*);window.userAvatar = '(.*)';";
                ret=Main.getSubUtil(result,rgex);
                String headpicBase64 = ret.get(1);
                Platform.runLater(
                        new Runnable() {
                            @Override
                            public void run() {
                                webEngine.loadContent("<img id='headpic' width='100%' height='100%' src='" + headpicBase64 + "' />");
                            }
                        }
                );

                this.waitPhoneAgree();
            }else if(ret.get(0).equals("200")){
                rgex = "window.code=(\\d*);window.redirect_uri=\"(.*)\";";
                ret = Main.getSubUtil(result, rgex);

                String redirect_uri = ret.get(1);
                rgex = "\\?ticket=(.*)&uuid=(.*)&lang=";
                List<String> ret2 = Main.getSubUtil(redirect_uri, rgex);
                this.ticket=ret2.get(0);
                this.webwxnewloginpage(redirect_uri);

            }else if(ret.get(0).equals("400") || ret.get(0).equals("408")){
                getUUID();
            }else{
                logger.error("error:"+ret.get(0));
            }
            return;

        }catch (MalformedURLException me){
            logger.debug(me.getMessage());
            this.waitScanQRCode();
        }catch(IOException e){
            logger.debug(e.getMessage());
            this.waitScanQRCode();
        }
    }


    /**
     * 等待手机端同意登陆
     */
    public void waitPhoneAgree(){
        this.tip=0;
        String url2="https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid="+this.uuid+"&tip="+this.tip+"&r=-1791540940&_=";
        String urlStr=url2+Long.toString(System.currentTimeMillis());
        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        String result="";
        logger.debug("request:"+urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            connection.disconnect();
            logger.debug("response:"+result);

            String rgex = "window.code=(\\d*);";
            List<String> ret = Main.getSubUtil(result, rgex);
            if (!ret.get(0).equals("200")) {
                System.out.println("waitPhoneAgree ret :"+ret.get(0));
                return ;
            }

            rgex = "window.code=(\\d*);window.redirect_uri=\"(.*)\";";
            ret = Main.getSubUtil(result, rgex);

            String redirect_uri = ret.get(1);
            rgex = "\\?ticket=(.*)&uuid=(.*)&lang=";
            List<String> ret2 = Main.getSubUtil(redirect_uri, rgex);
            this.ticket=ret2.get(0);
            this.webwxnewloginpage(redirect_uri);


        }catch (MalformedURLException me){

        }catch(IOException e){
            System.out.println(e.getMessage());
            if(e.getMessage().equals("Read timed out")){
                System.out.println("try again --waitPhoneAgree---");
                this.waitPhoneAgree();
            }
        }
    }

    private String domain="";
    public void webwxnewloginpage(String redirect_uri){
        String urlStr="";
        if(redirect_uri.startsWith("https://wx2.qq.com/")) {
            domain="https://wx2.qq.com";
        }else{
            domain="https://wx.qq.com";
        }
        urlStr=domain+"/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=" + this.ticket + "&uuid=" + this.uuid + "&lang=zh_CN&scan=1535353717&fun=new&version=v2&lang=zh_CN&jsonp=?";
        //urlStr=redirect_uri;
        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        String result="";

        logger.debug("request:"+urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            connection.disconnect();
            logger.debug("response:"+result);

            Document doc=null;
            try{
                doc= DocumentHelper.parseText(result);
                Element rootElt=doc.getRootElement();

                String ret = rootElt.elementTextTrim("ret");
                if (ret.equals("0")) {
                    String message = rootElt.elementTextTrim("message");
                    this.skey = rootElt.elementTextTrim("skey");
                    this.wxsid = rootElt.elementTextTrim("wxsid");
                    this.wxuin = rootElt.elementTextTrim("wxuin");
                    this.pass_ticket = rootElt.elementTextTrim("pass_ticket");
                    String isgrayscale = rootElt.elementTextTrim("isgrayscale");

                    System.out.println(skey);
                    System.out.println(wxsid);
                    System.out.println(wxuin);
                    System.out.println(pass_ticket);
                    this.webwxinit();
                }else{
                    alertMsg(rootElt.elementTextTrim("message"),"");
                    getUUID();
                }
            }catch(DocumentException e){

            }catch(Exception e){

            }
        }catch (MalformedURLException me){

        }catch(IOException e){
            System.out.println(e.getMessage());
            if(e.getMessage().equals("Read timed out")){
                System.out.println("try again --waitScanQRCode---");
                this.waitScanQRCode();
            }
        }
    }




    /**
     * 获取最新的聊天群和好友信息
     */
    private void webwxinit(){
        String urlStr=domain+"/cgi-bin/mmwebwx-bin/webwxinit?r=-2058443560&pass_ticket="+this.pass_ticket;
        Map<String,String> ms=new HashMap<>();
        ms.put("Uin",   this.wxuin);
        ms.put("Sid",   this.wxsid);
        ms.put("Skey",  this.skey);
        ms.put("DeviceID",this.getDeviceID());

        Map<String,Map<String,String>> m=new HashMap<>();
        m.put("BaseRequest",ms);

        logger.debug("request:"+urlStr);
        BufferedReader read=null;//读取访问结果
        try {
            URL url = new URL(urlStr);

            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            String payload= JSON.toJSONString(m);
            //System.out.println("payload:");
            //System.out.println(payload);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            connection.connect();

            StringBuffer sbf=new StringBuffer();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            read.close();
            connection.disconnect();
            String jsonStr=sbf.toString();
            logger.debug("response:"+jsonStr);

            this.initResponse=JSON.parseObject(jsonStr,Master.class);
            addToUserPool(this.initResponse.getContactList());


            String[] chatsetUserNames=this.initResponse.getChatSet().split(",");
            getUserDetail(chatsetUserNames);


            this.synckey=this.initResponse.getSyncKey();


            new Thread(() -> {
                try {
                    this.webwxgetcontact();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

            new Thread(() -> {
                try {
                    this.webwxstatusnotify();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();


        }catch(MalformedURLException me){
            System.out.println(me.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            if(e.getMessage().equals("Read timed out")){
                System.out.println("try again --waitScanQRCode---");
                this.waitScanQRCode();
            }
        }
    }

    private void getUserDetail(String username){
        String[] ul={username};
        getUserDetail(ul);
    }
    private void getUserDetail(ArrayList<String> username){
        ArrayList<String> ul=new ArrayList<>();
        for (String u:username) {
            if (u.equals("filehelper") || u.equals("weixin") || u.equals(""))continue;
            if (this.userShowNameMapping.get(u)==null){
                ul.add(u);
            }
        }
        if (ul.size()>0){
            webwxbatchgetcontact(ul);
        }
    }

    private void getUserDetail(String[] username){
        ArrayList<String> ul=new ArrayList<>();
        for (String u:username) {
            if (u.equals("filehelper") || u.equals("weixin") || u.equals(""))continue;
            if (this.userShowNameMapping.get(u)==null){
                ul.add(u);
            }
        }
        if (ul.size()>0){
            webwxbatchgetcontact(ul);
        }
    }



    private void webwxstatusnotify() {
        String urlStr=domain+"/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket="+this.pass_ticket;
        Map<String,String> ms=new HashMap<>();
        ms.put("Uin",   this.wxuin);
        ms.put("Sid",   this.wxsid);
        ms.put("Skey",  this.skey);
        ms.put("DeviceID",this.getDeviceID());

        Map<String,Object> m=new HashMap<>();
        m.put("BaseRequest",ms);
        m.put("Code",3);
        m.put("FromUserName",this.initResponse.getUser().getUin());
        m.put("ToUserName",this.initResponse.getUser().getUin());
        m.put("ClientMsgId",System.currentTimeMillis());

        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        try {
            URL url = new URL(urlStr);

            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            String payload= JSON.toJSONString(m);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            connection.connect();
            StringBuffer sbf=new StringBuffer();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            read.close();
            connection.disconnect();
            String jsonStr=sbf.toString();
            println(jsonStr);

            new Thread(() -> {
                try {
                    this.synccheck();
                    Thread.sleep(35000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

        }catch(MalformedURLException me){
            System.out.println(me.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            if(e.getMessage().equals("Read timed out")){
                System.out.println("try again --waitScanQRCode---");
                this.waitScanQRCode();
            }
        }


    }



    private void getSortedUserList(){
        List<Map.Entry<String, Contact>> list = new ArrayList<Map.Entry<String, Contact>>(this.userShowNameMapping.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Contact>>() {
            @Override
            public int compare(Map.Entry<String, Contact> o1, Map.Entry<String, Contact> o2) {
                return o1.getValue().getPriority()-o2.getValue().getPriority(); // 升序
            }
        });

        for (Map.Entry<String, Contact> mapping : list) {
            System.out.println(mapping.getKey() + ":" + mapping.getValue().getNickName());
        }
    }


    /**
     * 加入到用户池
     */
    private void addToUserPool(final ArrayList<Contact> cl){
        for(Contact member:cl){
            String userName=member.getUserName();
            if(userName.startsWith("@@")){//群组
                this.userShowNameMapping.put(userName,member);
            }else{//非群组
                if(member.getAttrStatus()>0) {
                    this.userShowNameMapping.put(userName,member);
                }else{
                    //公众号
                }
            }
        }
        getMaxUserIndex();
        showContactList();
    }
    private void clearUserPool(){
        this.userShowNameMapping.clear();
        this.UserIndex=0;
    }


    /**
     * 根据优先级排序，根据过滤筛选，最后显示
     */
    private void showContactList(){
        String filter=filterUser;
        ///////////////////////////////////////////////////////////////////////////////
        List<Map.Entry<String, Contact>> list = new ArrayList<Map.Entry<String, Contact>>(this.userShowNameMapping.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Contact>>() {
            @Override
            public int compare(Map.Entry<String, Contact> o1, Map.Entry<String, Contact> o2) {
                if (o1.getValue().hasNewMsg()==o2.getValue().hasNewMsg()) {
                    return o2.getValue().getPriority() - o1.getValue().getPriority(); // 降序
                }else{
                    return o2.getValue().hasNewMsg()-o1.getValue().hasNewMsg();// 降序
                }
            }
        });

        StringBuffer sbf=new StringBuffer();
        int contactNum=0;
        for (Map.Entry<String, Contact> mapping : list) {
            Contact c=mapping.getValue();
            if(!filter.equals("")) {//需要筛选
                if (c.getNickName().indexOf(filter) < 0 && c.getRemarkName().indexOf(filter) < 0) {
                    //不符合筛选跳过
                    continue;
                }
            }

            sbf.append("<a onclick='wxc.setCurrentUser(\""+c.getUserName()+"\")' ");
            if (c.hasNewMsg()==1){
                sbf.append(" style='color:red;font-weight:600' ");
            }
            sbf.append(">");

            sbf.append(c.getRemarkName());
            sbf.append("|");
            sbf.append(c.getNickName());
            sbf.append("</a><hr />");
            contactNum++;
        }
        list.clear();
        list=null;


        WebEngine we=this.contactView.getEngine();
        Main obj=this;
        int num=contactNum;
        Platform.runLater(
                new Runnable() {
                    @Override
                    public void run() {
                        we.getLoadWorker().stateProperty()
                                .addListener((obs, oldValue, newValue) -> {
                                    if (newValue == Worker.State.SUCCEEDED) {
                                        JSObject contactWindow = (JSObject) we.executeScript("window");
                                        contactWindow.setMember("wxc", obj);
                                    }});
                        //System.out.println(sbf.toString());
                        we.loadContent(sbf.toString());
                        ((Label)root.lookup("#info")).setText("联系人："+Integer.toString(num)+"   "+getLoadContactMsg());
                    }
                }
        );
    }

    private void getMaxUserIndex(){
        for(Contact m:userShowNameMapping.values())
        {
            String remarkName=m.getRemarkName();
            String[] tmp=remarkName.split("\\|\\|");
            if(isNumeric(tmp[0])){
                int index=Integer.parseInt(tmp[0]);
                if(index>this.UserIndex){
                    this.UserIndex=index;
                }
            }
        }
    }


    private String getLoadContactMsg(){
        if(seq.equals("-1")){
            return "好友名单加载完成";
        }
        return "好友名单加载中...";
    }

    private String seq="0";
    /**
     * 获取好友信息
     */
    private void webwxgetcontact(){
        String urlStr=domain+"/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&r="+Long.toString(System.currentTimeMillis())+"&seq="+seq+"&skey="+this.skey;
        logger.debug(urlStr);
        BufferedReader read=null;//读取访问结果
        String result="";
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(35000);
            connection.setReadTimeout(35000);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            read.close();
            connection.disconnect();
            String jsonStr=result;
            logger.debug("webwxgetcontact:"+jsonStr);

            ContactResponse cr=JSON.parseObject(jsonStr,ContactResponse.class);
            addToUserPool(cr.getMemberList());

            this.seq=Long.toString(cr.getSeq());
            if (!this.seq.equals("0")){
                webwxgetcontact();
            }else{
                this.seq="-1";
            }

        }catch (MalformedURLException me){

        }catch(IOException e){
            System.out.println(e.getMessage());
            if(e.getMessage().equals("Read timed out")){
                alertMsg("联系人加载失败","");
            }
        }
    }


    /**
     * 获取好友信息
     */
    private void webwxbatchgetcontact(ArrayList<String> ul){
        Map<String,String> baseRequest=new HashMap<>();
        baseRequest.put("Uin",      this.wxuin);
        baseRequest.put("Sid",      this.wxsid);
        baseRequest.put("Skey",     this.skey);
        baseRequest.put("DeviceID",this.getDeviceID());

        Map<String,Object> main=new HashMap<>();        ;
        main.put("BaseRequest",baseRequest);

        ArrayList<Map<String,String>>  concatlist=new ArrayList<>();
        for(String userName:ul){
            Map<String,String> u=new HashMap<>();
            u.put("UserName",userName);
            if(userName.startsWith("@@")) {
                u.put("EncryChatRoomId", "");
            }else{
                u.put("ChatRoomId", "");
            }

            concatlist.add(u);
        }
        main.put("List", concatlist);
        main.put("Count",concatlist.size());


        String urlStr=domain+"/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&lang=zh_CN&r="+Long.toString(System.currentTimeMillis())+"&pass_ticket="+this.pass_ticket;
        logger.debug("request:"+urlStr);
        BufferedReader read=null;//读取访问结果
        String result="";
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(15000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");


            String payload= JSON.toJSONString(main);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            read.close();
            connection.disconnect();

            String jsonStr=result;
            logger.debug(jsonStr);

            Batchgetcontact cr=JSON.parseObject(jsonStr,Batchgetcontact.class);
            addToUserPool(cr.getContactList());


        }catch (MalformedURLException me){

        }catch(IOException e){
            System.out.println(e.getMessage());
            if(e.getMessage().equals("Read timed out")){
                alertMsg("联系人加载失败","");
            }
        }
    }




    private String getSynckey(){
        SyncKey synckey=this.synckey;
        int num=synckey.getCount();
        ArrayList<SyncKeyList> sl= synckey.getList();
        StringBuffer bf=new StringBuffer();
        for(int i=1;i<=num;i++){
            SyncKeyList sitem=sl.get(i-1);
            String tmp=String.format("%d_%d",sitem.getKey(),sitem.getVal());
            bf.append(tmp);
            if(i<num){
                bf.append("%7C");
            }
        }
        return bf.toString();
    }

    /**
     * 消息检查
     */
    private void synccheck(){
        String synckey=this.getSynckey();
        String times=Long.toString(System.currentTimeMillis());
        String urlStr ="";
        if (domain.equals("https://wx2.qq.com")){
            urlStr="https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=" + times + "&skey=" + this.skey + "&sid=" + this.wxsid + "&uin=" + this.wxuin + "&deviceid=" + this.getDeviceID() + "&synckey=" + synckey + "&_=";
        }else {
            urlStr="https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=" + times + "&skey=" + this.skey + "&sid=" + this.wxsid + "&uin=" + this.wxuin + "&deviceid=" + this.getDeviceID() + "&synckey=" + synckey + "&_=";
        }
        urlStr +=times;
        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        String result="";
        logger.debug("request:"+urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(35000);
            connection.setReadTimeout(35000);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                result += line;
            }
            connection.disconnect();
/*
            window.synccheck={retcode:"xxx",selector:"xxx"}
            retcode:
            0 正常
            1100 失败/登出微信
            1101 从其它设备登录微信网页版
            selector:
            0 正常
            2 新的消息
            4 好友信息有变化
            7 手机操作了微信
*/

            logger.debug(result);

            if (result.equals("")){
                throw new IOException("no return");
            }
            String rgex = "window.synccheck=\\{retcode:\"(\\d*)\",selector:\"(\\d*)\"\\}";
            List<String> ret = Main.getSubUtil(result, rgex);

                if (ret.get(0).equals("1100") || ret.get(0).equals("1101") || ret.get(0).equals("1102")) {
                    //失败/登出微信
                    getUUID();
                    return;
                }


            switch (ret.get(1)){
                case "0":
                    new Thread(() -> {
                        try {
                            this.synccheck();
                            Thread.sleep(35000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }).start();
                    break;
                default:
                    this.webwxsync();
                    break;
            }
        }catch (MalformedURLException me){
            new Thread(() -> {
                try {
                    this.synccheck();
                    Thread.sleep(35000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }catch(IOException e){
            new Thread(() -> {
                try {
                    this.synccheck();
                    Thread.sleep(35000);
                } catch (InterruptedException ee) {
                    ee.printStackTrace();
                }
            }).start();
        }finally {
        }
    }

    /**
     * 信息同步显示
     */
    private void webwxsync(){

        Map<String,String> baseRequest=new HashMap<>();
        baseRequest.put("Uin",      this.wxuin);
        baseRequest.put("Sid",      this.wxsid);
        baseRequest.put("Skey",     this.skey);
        baseRequest.put("DeviceID",this.getDeviceID());

        Map<String,Object> main=new HashMap<>();        ;
        main.put("BaseRequest",baseRequest);
        if(null==this.synccheckkey) {
            main.put("SyncKey", this.synckey);
        }else{
            main.put("SyncKey", this.synccheckkey);
        }
        main.put("rr",this.getTimeStampReverse());
        String urlStr=domain+"/cgi-bin/mmwebwx-bin/webwxsync?sid="+this.wxsid+"&skey="+this.skey;

        BufferedReader read=null;//读取访问结果
        logger.debug("request:"+urlStr);
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("GET");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");


            String payload= JSON.toJSONString(main);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            //建立连接
            connection.connect();
            read = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;//循环读取
            StringBuffer sbf=new StringBuffer();
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            connection.disconnect();
            String jsonStr=sbf.toString();

            logger.debug("reaponse:"+jsonStr);
            WebwxsyncResponse syncResponse=JSON.parseObject(jsonStr,WebwxsyncResponse.class);
            this.synckey=syncResponse.getSynckey();
            this.synccheckkey=syncResponse.getSyncCheckKey();
            if (syncResponse.getModContactCount()>0){
                addToUserPool(syncResponse.getModContactList());
            }

            this.processMsg(syncResponse);

        }catch (MalformedURLException e){
            logger.debug(e.getMessage());
        }catch(IOException e){
            logger.debug(e.getMessage());
        }finally {
            new Thread(() -> {
                try {
                    this.synccheck();
                    Thread.sleep(35000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }


    private Map<String,StringBuffer> userMsgLogList=new HashMap<>();

    private String currentUser="";
    private void showMsg(){
        WebEngine we=this.chatView.getEngine();
        StringBuffer sbf=this.userMsgLogList.get(this.currentUser);
        String html="";
        if (sbf!=null){
            html=sbf.toString();
        }
        String content=html;
        Platform.runLater(
                new Runnable() {
                    @Override
                    public void run() {
                        we.loadContent(content);
                    }
                }
        );

    }
    private void processMsg(WebwxsyncResponse response){
        int num=response.getAddMsgCount();
        if (num<=0)return;
        ArrayList<AddMsgList_item> msg=response.getAddMsgList();

        ArrayList<String> usernamelist=new ArrayList<>();
        for(int i=0;i<num;i++){
            AddMsgList_item item= msg.get(i);
            usernamelist.add(item.getFromUserName());
            usernamelist.add(item.getToUserName());

            MsgLogItem ml=new MsgLogItem();
            ml.setContent(item.getContent());
            ml.setCreateTime(item.getCreateTime());
            ml.setMsgType(item.getMsgType());
            ml.setFromUserName(item.getFromUserName());
            ml.setToUserName(item.getToUserName());

            if(item.getMsgType()!=AddMsgList_item.MSGTYPE_TEXT){
                 ml.setContent("请在手机中查看");
                 if(item.getMsgType()==AddMsgList_item.MSGTYPE_VERIFYMSG) {
                     if (item.getFromUserName().equals("fmessage") && item.getToUserName().equals(initResponse.getUser().getUserName())) {
                         agreeFriend(item.getRecommendInfo().getUserName(), item.getRecommendInfo().getTicket());
                     }
                 }else if(item.getMsgType()==AddMsgList_item.MSGTYPE_STATUSNOTIFY){//一些确认消息跳过
                     continue;
                 }else if(item.getMsgType()==AddMsgList_item.MSGTYPE_SYS && item.getContent().startsWith("收到红包")){
                     ml.setContent(item.getContent());
                     Contact fr=userShowNameMapping.get(item.getFromUserName());
                     String detail="";
                     if(fr!=null){
                         detail="来自："+fr.getRemarkName()+","+fr.getNickName()+"的红包";
                     }
                     alertMsg(item.getContent(),detail);
                 }else if(item.getMsgType()==AddMsgList_item.MSGTYPE_APP && item.getContent().indexOf("微信转账")>=0){
                     ml.setContent("请到微信转账，请到手机端接收");
                     Contact fr=userShowNameMapping.get(item.getFromUserName());
                     String detail="";
                     if(fr!=null){
                         detail="来自："+fr.getRemarkName()+","+fr.getNickName()+"的转账";
                     }
                     alertMsg("请到微信转账，请到手机端接收",detail);
                 }else if(item.getMsgType()==AddMsgList_item.MSGTYPE_IMAGE){
                     ml.setContent("<img src='https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetmsgimg?&MsgID="+item.getMsgId()+"&skey="+this.skey+"&type=slave' />");
                 }
            }

            /////////////////////////////对方
            String selfUserName=this.initResponse.getUser().getUserName();
            String targetUserName="";
            String pos="";
            if (item.getFromUserName().equals(selfUserName)){
                targetUserName=item.getToUserName();
                pos="style='text-align:right;background-color:lightblue'";
            }else{
                targetUserName=item.getFromUserName();
                pos="";
            }

            Contact other=this.userShowNameMapping.get(targetUserName);
            if(other!=null) {
                other.setNewMsg(1);
                other.plusPriority();
            }


            String format = "yyyy-MM-dd HH:mm:ss";
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            ////////////////////////发送者////////////////////////////////////
            Contact sender=this.userShowNameMapping.get(item.getFromUserName());
            String writer="";
            if(sender==null){
                writer="未知";
            }else{
                writer=sender.getRemarkName()+"|"+sender.getNickName();
            }
            long second=ml.getCreateTime();


            String timestr= sdf.format(new Date(Long.valueOf(second+"000")));
            String content=String.format("<hr /><div "+pos+"> <div class='user'>%s  %s</div> <div class='content'>%s</div></div>",writer,timestr,ml.getContent());

            StringBuffer ul=this.userMsgLogList.get(targetUserName);
            if(ul==null){
                ul=new StringBuffer();
                ul.append(content);
                this.userMsgLogList.put(targetUserName,ul);
            }else{
                ul.append(content);
            }

//            ////////////////////////接收者////////////////////////////////////
//            if (!item.getToUserName().equals(item.getFromUserName())) {
//                content = String.format("<hr /><div class='right' style='text-align:right;background-color:lightblue'> <div class='user'>%s  %s</div> <div class='content'>%s</div></div>", writer, timestr, ml.getContent());
//                StringBuffer ul2 = this.userMsgLogList.get(targetUserName);
//                if (ul2 == null) {
//                    ul2 = new StringBuffer();
//                    ul2.append(content);
//                    this.userMsgLogList.put(targetUserName, ul2);
//                } else {
//                    ul2.append(content);
//                }
//            }


            if(item.getMsgType()==AddMsgList_item.MSGTYPE_TEXT) {
                logger.debug(":文本信息");
                if (ml.getToUserName().equals(this.initResponse.getUser().getUserName()) && !ml.getFromUserName().equals(this.initResponse.getUser().getUserName())) {
                    ArrayList<Reply> replyList = filteMsgReply(ml.getContent());
                    if (replyList != null) {
                        for (Reply r : replyList) {
                            if (r.getType().equals("文本")) {
                                logger.debug("response:文本");
                                webwxsendmsg(ml.getToUserName(), ml.getFromUserName(), r.getContent());
                            } else {
                                logger.debug("response:图片");
                                webwxsendimg(ml.getToUserName(), ml.getFromUserName(), r.getContent());
                            }
                        }
                    }
                }
            }
            this.showMsg();
            showContactList();
        }
        //取未知用户
        getUserDetail(usernamelist);


    }


    private ArrayList<Reply> filteMsgReply(String msgContent){
        for(ReplyRule r:this.appConfig.getReplyList()){
            if(r.match(msgContent)){
                return r.getReply();
            }
        }
        return null;
    }

    /**
     * 正则表达式匹配两个指定字符串中间的内容
     *
     * @param soap
     * @return
     */
    public static List<String> getSubUtil(String soap, String rgex) {

        List<String> list = new ArrayList<String>();
        Pattern pattern = Pattern.compile(rgex);// 匹配的模式
        Matcher m = pattern.matcher(soap);
        while (m.find()) {
            for(int i = 1;i<=m.groupCount();i++) {
                list.add(m.group(i));
            }
        }
        return list;
    }


    public boolean isNumeric(String str){
        Pattern pattern = Pattern.compile("^[1-9]\\d*");
        Matcher isNum = pattern.matcher(str);
        if( !isNum.matches() ){
            return false;
        }
        return true;
    }


    private Iterator entries;
    public void resetAllUserRemarkName(){
        entries=this.userShowNameMapping.entrySet().iterator();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        Timer timer = new Timer();
                        timer.schedule(new RemarkTask(),0,21000);
                    }
                }
        ).start();
    }

    class RemarkTask extends  TimerTask{
        @Override
        public void run() {
            if (entries.hasNext()){
                Map.Entry entry=(Map.Entry) entries.next();
                String userName = (String)entry.getKey();
                resetOneUserRemarkName(userName);

            }else{
                System.out.println("修改备注定时器结束---");
                //timer.cancel();
            }
        }
    }


    public void resetOneUserRemarkName(String userName){
        String remarkName="";
        Contact member=this.userShowNameMapping.get(userName);
        if(null==member){
            return;
        }
        String oldRemarkName=member.getRemarkName();
        String[] tmp=oldRemarkName.split("\\|\\|");
        if(tmp.length==1){//全新用户
            this.UserIndex++;
            remarkName=this.UserIndex+"||"+oldRemarkName;
            editRemark(userName,remarkName);
        }else {//
            if(!isNumeric(tmp[0])){
                this.UserIndex++;
                remarkName=this.UserIndex+"||"+tmp[1];
                editRemark(userName,remarkName);
            }
        }
    }



    public static int UserIndex=0;
    public void setCurrentUser(String userName){
        this.currentUser=userName;

       Label l=(Label)root.lookup("#targetShow");
       String t=this.userShowNameMapping.get(userName).getRemarkName()+"|"+this.userShowNameMapping.get(userName).getNickName();
       l.setText("     当前的聊天对象是："+t);
       showMsg();
       if(this.userShowNameMapping.get(currentUser).hasNewMsg()==1) {
           this.userShowNameMapping.get(currentUser).setNewMsg(0);
           showContactList();
       }
    }


    /**
     * 发送文字信息
     * @param fromUserName
     * @param toUserName
     * @param content
     */
    public void webwxsendmsg(String fromUserName,String toUserName,String content){
        String urlStr=this.domain+"/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket="+this.pass_ticket;
        Map<String,String> baseRequest=new HashMap<>();
        baseRequest.put("Uin",   this.wxuin);
        baseRequest.put("Sid",   this.wxsid);
        baseRequest.put("Skey",  this.skey);
        baseRequest.put("DeviceID",this.getDeviceID());

        String msgid=System.currentTimeMillis()+""+(long)Math.random()*1000;

        Map<String,Object> msg=new HashMap<>();
        msg.put("Type",   AddMsgList_item.MSGTYPE_TEXT);
        msg.put("Content",   content);
        msg.put("FromUserName",  fromUserName);
        msg.put("ToUserName",toUserName);
        msg.put("ClientMsgId",msgid);
        msg.put("LocalID",msgid);

        Map<String,Object> m=new HashMap<>();
        m.put("BaseRequest",baseRequest);
        m.put("Scene",0);
        m.put("Msg",msg);

        logger.debug("request:"+urlStr);
        BufferedReader read=null;//读取访问结果
        try {
            URL url = new URL(urlStr);

            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            String payload= JSON.toJSONString(m);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            connection.connect();
            StringBuffer sbf=new StringBuffer();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            read.close();
            connection.disconnect();
            String jsonStr=sbf.toString();
            logger.debug("response:"+jsonStr);


            String format = "yyyy-MM-dd HH:mm:ss";
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            ////////////////////////发送者////////////////////////////////////
            Contact u=this.userShowNameMapping.get(fromUserName);
            String author="";
            if(u==null){
                author="未知";
            }else{
                author=u.getNickName();
            }
            long second=System.currentTimeMillis();

            String timestr= sdf.format(new Date(Long.valueOf(second+"000")));
            String contentstr=String.format("<hr /><div class='right' style='text-align:right;background-color:lightblue'> <div class='user'>%s 于 %s</div> <div class='content'>%s</div></div>",author,timestr,content);

            StringBuffer ul=this.userMsgLogList.get(toUserName);
            if(ul==null){
                ul=new StringBuffer();
                ul.append(contentstr);
                this.userMsgLogList.put(toUserName,ul);
            }else{
                ul.append(contentstr);
            }


        }catch(MalformedURLException e){
            logger.debug(e.getMessage());
        }catch(Exception e){
            logger.debug(e.getMessage());
        }
    }

    public void webwxsendimg(String fromUserName,String toUserName,String filePath){
        File chosenFile=new File(filePath);
        webwxsendimg(fromUserName,toUserName,chosenFile);
    }
    public void webwxsendimg(String fromUserName,String toUserName,File chosenFile){
        if (chosenFile==null){
            return;
        }
        String filename = chosenFile.getName();

        System.out.println(chosenFile.getAbsolutePath());
            //C:\Users\Administrator\Pictures\lg.png
            Map<String,Object > textMap=new HashMap<>();
            textMap.put("id","WU_FILE_0");
            textMap.put("name",chosenFile.getName());

            String contentType = new MimetypesFileTypeMap().getContentType(chosenFile);
            //contentType非空采用filename匹配默认的图片类型
            if(!"".equals(contentType)){
                if (filename.endsWith(".png")) {
                    contentType = "image/png";
                }else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".jpe")) {
                    contentType = "image/jpeg";
                }else if (filename.endsWith(".gif")) {
                    contentType = "image/gif";
                }else if (filename.endsWith(".ico")) {
                    contentType = "image/image/x-icon";
                }
            }
            if (contentType == null || "".equals(contentType)) {
                contentType = "application/octet-stream";
            }

            textMap.put("type",contentType);
            textMap.put("lastModifiedDate",this.getFileLastModifiedTimeStr(chosenFile));
            textMap.put("size",chosenFile.getTotalSpace());
            textMap.put("mediatype","pic");
            textMap.put("pass_ticket",pass_ticket);
//---------------------------------------------------------------------------------
            Map<String,String> baseRequest=new HashMap<>();
            baseRequest.put("Uin",   this.wxuin);
            baseRequest.put("Sid",   this.wxsid);
            baseRequest.put("Skey",  this.skey);
            baseRequest.put("DeviceID",this.getDeviceID());


            Map<String,Object> m=new HashMap<>();
            m.put("UploadType",2);
            m.put("BaseRequest",baseRequest);
            m.put("ClientMediaId",System.currentTimeMillis());
            m.put("TotalLen",chosenFile.getTotalSpace());
            m.put("StartPos",0);
            m.put("DataLen",chosenFile.getTotalSpace());
            m.put("MediaType",4);
            m.put("FromUserName",fromUserName);
            m.put("ToUserName",toUserName);
            try {
                m.put("FileMd5", DigestUtils.md5Hex(new FileInputStream(chosenFile.getAbsolutePath())));
            }catch(FileNotFoundException fe) {
                fe.printStackTrace();
                return;
            }catch (IOException e) {
                e.printStackTrace();
                return;
            }

            textMap.put("uploadmediarequest",JSON.toJSONString(m));
//---------------------------------------------------------------------------------


            Map<String,String> fileMap=new HashMap<>();
            fileMap.put("filename",chosenFile.getAbsolutePath());
            String jsonStr ="";
            if (domain.equals("https://wx2.qq.com")){
                jsonStr = UploadUtil.formUpload("https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json", textMap, fileMap, contentType);
            }else{
                jsonStr = UploadUtil.formUpload("https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json", textMap, fileMap, contentType);
            }



            UploadMediaReturn mediaReturn=JSON.parseObject(jsonStr,UploadMediaReturn.class);


            String msgid=System.currentTimeMillis()+""+Math.random()*1000;
            Map<String,Object> msg=new HashMap<>();
            msg.put("Type",   AddMsgList_item.MSGTYPE_IMAGE);
            msg.put("Content",   "");
            msg.put("FromUserName",  fromUserName);
            msg.put("ToUserName",toUserName);
            msg.put("ClientMsgId",msgid);
            msg.put("LocalID",msgid);
            msg.put("MediaId",mediaReturn.getMediaId());

            Map<String,Object> main=new HashMap<>();
            main.put("BaseRequest",   baseRequest);
            main.put("Msg",   msg);
            main.put("Scene",   0);

        String urlStr=this.domain+"/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&lang=zh_CN&pass_ticket="+this.pass_ticket;
        BufferedReader read=null;//读取访问结果
        try {
            URL url = new URL(urlStr);

            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(2000);
            connection.setReadTimeout(2000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            String payload= JSON.toJSONString(main);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            connection.connect();
            StringBuffer sbf=new StringBuffer();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            read.close();
            connection.disconnect();
            String retStr=sbf.toString();
            println(retStr);







            String format = "yyyy-MM-dd HH:mm:ss";
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            ////////////////////////发送者////////////////////////////////////
            Contact u=this.userShowNameMapping.get(fromUserName);
            String author="";
            if(u==null){
                author="未知";
            }else{
                author=u.getNickName();
            }
            long second=System.currentTimeMillis();;

            String timestr= sdf.format(new Date(Long.valueOf(second+"000")));
            String content="[发送了图片,请在手机中查看]";
            String contentstr=String.format("<hr /><div class='right' style='text-align:right;background-color:lightblue'> <div class='user'>%s 于 %s</div> <div class='content'>%s</div></div>",author,timestr,content);

            StringBuffer ul=this.userMsgLogList.get(toUserName);
            if(ul==null){
                ul=new StringBuffer();
                ul.append(contentstr);
                this.userMsgLogList.put(toUserName,ul);
            }else{
                ul.append(contentstr);
            }






        }catch(MalformedURLException e){
            logger.debug(e.getMessage());
        }catch(Exception e){
            logger.debug(e.getMessage());
        }
    }



    public void editRemark(String username,String remarkName){
        System.out.println(username+" --==-- "+remarkName);
        String urlStr="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxoplog?lang=zh_CN&pass_ticket="+this.pass_ticket;
        Map<String,String> baseRequest=new HashMap<>();
        baseRequest.put("Uin",   this.wxuin);
        baseRequest.put("Sid",   this.wxsid);
        baseRequest.put("Skey",  this.skey);
        baseRequest.put("DeviceID",this.getDeviceID());


        Map<String,Object> main=new HashMap<>();
        main.put("BaseRequest",baseRequest);
        main.put("CmdId",2);
        main.put("RemarkName",remarkName);
        main.put("UserName",username);

        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        try {
            URL url = new URL(urlStr);

            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(10000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            String payload= JSON.toJSONString(main);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            connection.connect();
            StringBuffer sbf=new StringBuffer();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            read.close();
            connection.disconnect();
            String jsonStr=sbf.toString();
            println(jsonStr);


        }catch(MalformedURLException me){
            System.out.println(me.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            if(e.getMessage().equals("Read timed out")){
                System.out.println("try again --waitScanQRCode---");
                this.waitScanQRCode();
            }
        }
    }


    private void saveConfig(){
        String jsonStr=JSON.toJSONString(this.appConfig);
        File file =new File(this.cfgFileName);

        try {
            if (!file.exists()) {
                file.createNewFile();
            }

            FileOutputStream writerStream = new FileOutputStream(file);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(writerStream, "UTF-8"));
            writer.write(jsonStr);
            writer.close();


        }catch (IOException e){
            e.printStackTrace();
        }
    }

    private void loadConfig(){
        String jsonStr=readToString(this.cfgFileName);
        if (jsonStr==null){
            this.appConfig=new AppConfig();
            return;
        }
        this.appConfig=JSON.parseObject(jsonStr,AppConfig.class);
    }

    public String readToString(String fileName) {
        String encoding = "UTF-8";
        File file = new File(fileName);
        if(!file.exists()){
            return "";
        }
        Long filelength = file.length();
        byte[] filecontent = new byte[filelength.intValue()];
        try {
            FileInputStream in = new FileInputStream(file);
            in.read(filecontent);
            in.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            return new String(filecontent, encoding);
        } catch (UnsupportedEncodingException e) {
            System.err.println("The OS does not support " + encoding);
            e.printStackTrace();
            return null;
        }
    }

    private String getFileLastModifiedTimeStr(File file) {
        long lm = file.lastModified();
        Calendar cd = Calendar.getInstance();
        cd.setTimeInMillis(lm);
        SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String timeStr = sdf.format(cd.getTime());
        return timeStr;
    }


    /**
     * 同意加好友
     */
    private void agreeFriend(String userValue,String VerifyUserTicket ){
        Map<String,String> baseRequest=new HashMap<>();
        baseRequest.put("Uin",      this.wxuin);
        baseRequest.put("Sid",      this.wxsid);
        baseRequest.put("Skey",     this.skey);
        baseRequest.put("DeviceID",this.getDeviceID());

        Map<String,Object> main=new HashMap<>();        ;
        main.put("BaseRequest",baseRequest);
        main.put("Opcode",3);
        main.put("VerifyUserListSize",1);
            Map<String,String> fuser=new HashMap<>() ;
            fuser.put("Value",userValue);
            fuser.put("VerifyUserTicket",VerifyUserTicket);
            ArrayList<Map<String,String>> userlist=new ArrayList<>();
            userlist.add(fuser);
        main.put("VerifyUserList",userlist);
        main.put("SceneList",new int[]{33});
        main.put("SceneListCount",1);
        main.put("skey",this.skey);
        main.put("VerifyContent","");


        String urlStr=this.domain+"/cgi-bin/mmwebwx-bin/webwxverifyuser?r="+System.currentTimeMillis();
        System.out.println(urlStr);
        BufferedReader read=null;//读取访问结果
        try {
            URL url = new URL(urlStr);

            HttpURLConnection connection=(HttpURLConnection)url.openConnection();
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(10000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

            String payload= JSON.toJSONString(main);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            writer.write(payload);
            writer.flush();
            writer.close();

            connection.connect();
            StringBuffer sbf=new StringBuffer();
            read = new BufferedReader(new InputStreamReader( connection.getInputStream(),"UTF-8"));
            String line;//循环读取
            while ((line = read.readLine()) != null) {
                sbf.append(line);
            }
            read.close();
            connection.disconnect();
            String jsonStr=sbf.toString();
            logger.debug("response:加好友请求，自动同意");
            logger.debug("response2:"+jsonStr);


        }catch(MalformedURLException me){
            System.out.println(me.getMessage());
        }catch(Exception e){
            e.printStackTrace();
            if(e.getMessage().equals("Read timed out")){
                System.out.println("try again --waitScanQRCode---");
                this.waitScanQRCode();
            }
        }

    }

}




